import json
import os.path
from typing import Dict, List, Union, Optional, TypeVar, Type

T = TypeVar('T', bound='JsonObject')

class JsonObject:
    @classmethod
    def from_dict(cls: Type[T], data) -> T:
        obj = cls()
        for key, value in data.items():
            if isinstance(value, dict):
                setattr(obj, key, JsonObject.from_dict(value))
            elif isinstance(value, (list, tuple)):
                setattr(obj, key, [
                    JsonObject.from_dict(item) if isinstance(item, dict) else item
                    for item in value
                ])
            else:
                setattr(obj, key, value)
        return obj

    @classmethod
    def from_json(cls: Type[T], json_str: str) -> T:
        return cls.from_dict(json.loads(json_str))

    @classmethod
    def from_file(cls: Type[T], filename: str) -> T:
        if not os.path.exists(filename):
            return None
        data = None
        with open(filename, 'r', encoding='utf-8') as f:
            data = json.load(f)
        if data is None:
            return None
        return cls.from_dict(data)


    def to_dict(self) -> dict:
        result = {}
        for key, value in self.__dict__.items():
            if isinstance(value, JsonObject):
                result[key] = value.to_dict()
            elif isinstance(value, (list, tuple)):
                result[key] = [
                    item.to_dict() if isinstance(item, JsonObject) else item
                    for item in value
                ]
            else:
                result[key] = value
        return result

    def to_json(self, indent: Optional[int] = None) -> str:
        return json.dumps(self.to_dict(), indent=indent, ensure_ascii=False)

    def __repr__(self) -> str:
        return f"{self.__class__.__name__}({self.__dict__})"